#include<stdlib.h>
#include<stdio.h>
//#include<stdint.h>
#include<string.h>
#include "mifare.h"
/**
 ****************************************************************
 * @brief pcd_auth_state()
 *
 * 功能：用存放在FIFO中的密钥和卡上的密钥进行验证
 *
 * @param: auth_mode=验证方式,0x60:验证A密钥,0x61:验证B密钥
 * @param: block=要验证的绝对块号
 * @param: psnr=序列号首地址,即UID
 * @return: status 值为MI_OK:成功
 *
 ****************************************************************
 */
int8_t pcd_auth_state(uint8_t auth_mode, uint8_t block, uint8_t *psnr, uint8_t *pkey)
{
    int8_t status = MI_EMPTY;
    uint8_t i;
    transceive_buffer  mf_com_data;
    transceive_buffer  *pi;
    pi = &mf_com_data;

    #if (NFC_DEBUG)
    printf("AUTH: >> ");
    #endif
    spi_write_reg(fifolevel_reg, 0x80);             //clear fifo data
    spi_write_reg(crcpreset_reg, CRC_A);   			//crc初值配置

    mf_com_data.mf_command = PCD_AUTHENT;
    mf_com_data.mf_length = 12;
    mf_com_data.mf_data[0] = auth_mode;
    mf_com_data.mf_data[1] = block;

    for(i = 0; i < 6; i++)
    {
        mf_com_data.mf_data[2 + i] = pkey[i];
    }
    memcpy(&mf_com_data.mf_data[8], psnr, 4);
    status = pcd_com_transceive(pi);
    return status;
}

/**
 ****************************************************************
 * @brief pcd_write_block()
 *
 * 功能：写数据到卡上的一块
 *
 * @param: addr = 要写的绝对块号
 * @param: pwritedata = 存放写的数据缓存区的首地址
 * @return: status 值为MI_OK:成功
 *
 ****************************************************************
 */
int8_t pcd_write_block(unsigned char b_num, unsigned char *block_inf)
{
    unsigned char crc_lsb = 0;
    unsigned char crc_msb = 0;
    int8_t status = MI_EMPTY;
    uint8_t i;
    transceive_buffer  mf_com_data;
    transceive_buffer  *pi;
    pi = &mf_com_data;

    spi_write_reg(fifolevel_reg, 0x80);                    //clear fifo data
    spi_write_reg(snd_byte_num_reg, 0x04);   //4bytes
    spi_write_reg(snd_bit_num_reg, 0x00);    //0bit

    mf_com_data.mf_command = PCD_TRANSCEIVE;
    mf_com_data.mf_length = 4;
    mf_com_data.mf_data[0] = PICC_WRITE;                     //写一个块命令
    mf_com_data.mf_data[1] = b_num;                    //块地址

    pcd_get_crc(CRC_A, 2, mf_com_data.mf_data, &crc_lsb, &crc_msb);
    mf_com_data.mf_data[2] = crc_lsb;
    mf_com_data.mf_data[3] = crc_msb;

    status = pcd_com_transceive(pi);

    if(MI_OK == status)
    {
        if((mf_com_data.mf_data[0] & 0x0F) == 0x0A)
        {
            mf_com_data.mf_command = PCD_TRANSCEIVE;
            mf_com_data.mf_length = 18;

            for(i = 0; i < 16; i++)
            {
                mf_com_data.mf_data[i] = block_inf[i];              //要写入到块中的数据
            }

            spi_write_reg(fifolevel_reg, 0x80);                    //clear fifo data
            spi_write_reg(snd_byte_num_reg, 0x12);        //18bytes
            spi_write_reg(snd_bit_num_reg, 0x00); 	      //0bit

            pcd_get_crc(CRC_A, 16, mf_com_data.mf_data, &crc_lsb, &crc_msb);
            mf_com_data.mf_data[16] = crc_lsb;
            mf_com_data.mf_data[17] = crc_msb;

            status = pcd_com_transceive(pi);

            if(MI_OK == status)
            {
                if((mf_com_data.mf_data[0] & 0x0F) == 0x0A)
                {
                    return MI_OK;
                }
                else
                {
                    return MI_WRITEERR;
                }
            }
            else
            {
                return status;
            }
        }
        else
        {
            return MI_WRITEERR;
        }
    }
    else
    {
        return status;
    }
}

/**
 ****************************************************************
 * @brief pcd_read_block()
 *
 * 功能：读mifare_one卡上一块(block)数据(16字节)
 *
 * @param: b_num = 要读的绝对块号
 * @param: block_inf = 存放读出的数据缓存区的首地址
 * @return: status 值为MI_OK:成功
 * @retval: block_inf  读出的数据
 *
 ****************************************************************
 */
int8_t pcd_read_block(uint8_t b_num, uint8_t *block_inf)
{
    unsigned char crc_lsb = 0;
    unsigned char crc_msb = 0;
    int8_t status = MI_EMPTY;
    transceive_buffer  mf_com_data;
    transceive_buffer  *pi;
    pi = &mf_com_data;

    spi_write_reg(fifolevel_reg, 0x80);                    //clear fifo data
    spi_write_reg(recstate_reg, 0x7F);
    spi_write_reg(snd_byte_num_reg, 0x04);   //4bytes
    spi_write_reg(snd_bit_num_reg, 0x00);    //0bit

    mf_com_data.mf_command = PCD_TRANSCEIVE;
    mf_com_data.mf_length = 4;
    mf_com_data.mf_data[0] = PICC_READ;                            //读块命令--0x30
    mf_com_data.mf_data[1] = b_num;                           //块号即块地址

    pcd_get_crc(CRC_A, 2, mf_com_data.mf_data, &crc_lsb, &crc_msb);
    mf_com_data.mf_data[2] = crc_lsb;
    mf_com_data.mf_data[3] = crc_msb;
    status = pcd_com_transceive(pi);

    if(MI_OK == status)
    {
        memcpy(block_inf, mf_com_data.mf_data, mf_com_data.mf_length);
        return MI_OK;
    }
    else
    {
        return status;
    }
}

/****************************************************************
* @brief pcd_set_value_block()
*
* 功能：m1设置值块，值块只能通过以值块格式进行写操作来生成
*
* @param: b_num = 要写的绝对块号
* @param: block_inf = 存放写入的数据缓存区的首地址
* @return: status 值为MI_OK:成功
* @retval: block_inf  写入的数据
*
****************************************************************
*/
//值块格式：数据值用4字节符号数据表示，地位有效数据在低地址；块地址值用1字节表示，具体看S50文档VALUE BLOCK解释
int8_t pcd_set_value_block(unsigned char b_num, unsigned char *block_inf)
{
    unsigned char i, block_val[16] = {0};
    int8_t status = MI_EMPTY;

    for(i = 0; i < 4; i++)
    {
        block_val[i] = block_inf[i];
        block_val[i + 4] = 255 - block_inf[i];
        block_val[i + 8] = block_inf[i];
    }

    block_val[12] = b_num;
    block_val[13] = 255 - b_num;
    block_val[14] = block_val[12];
    block_val[15] = block_val[13];
    status = pcd_write_block(b_num, block_val);

    return status;
}
/****************************************************************
* @brief pcd_transfer_block()
*
* 功能：把计算的结果从TRANSFER_BUF中写回到某个块，让某个块变成值块
*
* @param: b_num = 要写的绝对块号
* @return: status 值为MI_OK:成功
*
****************************************************************
*/
int8_t pcd_transfer_block(unsigned char b_num)
{

    unsigned char crc_lsb = 0;
    unsigned char crc_msb = 0;
    int8_t status = MI_EMPTY;
    transceive_buffer  mf_com_data;
    transceive_buffer  *pi;
    pi = &mf_com_data;

    spi_write_reg(fifolevel_reg, 0x80);                    //clear fifo data
    spi_write_reg(recstate_reg, 0x7F);
    spi_write_reg(snd_byte_num_reg, 0x04);           //4bytes
    spi_write_reg(snd_bit_num_reg, 0x00);            //0bit

    mf_com_data.mf_command = PCD_TRANSCEIVE;
    mf_com_data.mf_length = 4;
    mf_com_data.mf_data[0] = PICC_TRANSFER;                                     //transfer command
    mf_com_data.mf_data[1] = b_num;

    pcd_get_crc(CRC_A, 2,  mf_com_data.mf_data, &crc_lsb, &crc_msb);
    mf_com_data.mf_data[2] = crc_lsb;
    mf_com_data.mf_data[3] = crc_msb;

    status = pcd_com_transceive(pi);

    if(MI_OK == status)
    {
        if((mf_com_data.mf_data[0] & 0x0f) == 0x0A)
        {
            return MI_OK;
        }
        else
        {
            return MI_TRANSERR;
        }
    }
    else
    {
        return MI_TRANSERR;
    }
}
/////////////////////////////////////////////////////////////////////
//功    能：扣款和充值
//参数说明: dd_mode[IN]：命令字
//               0xC0 = 扣款
//               0xC1 = 充值
//          addr[IN]：钱包地址
//          pValue[IN]：4字节增(减)值，低位在前
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
int8_t pcd_value(unsigned char dd_mode, unsigned char addr, unsigned char *pValue)
{
    unsigned char crc_lsb = 0;
    unsigned char crc_msb = 0;
    int8_t status;
    transceive_buffer  mf_com_data;
    transceive_buffer  *pi;
    pi = &mf_com_data;

    spi_write_reg(fifolevel_reg, 0x80);                    //clear fifo data
    spi_write_reg(recstate_reg, 0x7F);
    spi_write_reg(snd_byte_num_reg, 0x04);           //4bytes
    spi_write_reg(snd_bit_num_reg, 0x00);            //0bit

    mf_com_data.mf_command = PCD_TRANSCEIVE;
    mf_com_data.mf_length  = 4;
    mf_com_data.mf_data[0] = dd_mode;
    mf_com_data.mf_data[1] = addr;
    pcd_get_crc(CRC_A, 2,  mf_com_data.mf_data, &crc_lsb, &crc_msb);
    mf_com_data.mf_data[2] = crc_lsb;
    mf_com_data.mf_data[3] = crc_msb;

    status = pcd_com_transceive(pi);

    if(status == MI_OK)
    {
        if((mf_com_data.mf_data[0] & 0x0f) == 0x0A)
        {
            spi_write_reg(recstate_reg, 0x7F);
            spi_write_reg(snd_byte_num_reg, 0x06);           //4bytes
            spi_write_reg(snd_bit_num_reg, 0x00);            //0bit

            mf_com_data.mf_command = PCD_TRANSMIT;
            mf_com_data.mf_length  = 6;
            memcpy(&mf_com_data.mf_data[0], pValue, 4);
            pcd_get_crc(CRC_A, 4,  mf_com_data.mf_data, &crc_lsb, &crc_msb);
            mf_com_data.mf_data[4] = crc_lsb;
            mf_com_data.mf_data[5] = crc_msb;
            status = pcd_com_transceive(pi);
            Delay_ms(50);//只发送不接收，稍微延时

            if(status == MI_OK)
            {
                status = pcd_transfer_block(addr);

                if(MI_OK == status)
                {
                    return MI_OK;
                }
            }
            else
            {
                status = MI_COM_ERR;
            }

        }
        else
        {
            status = PROTOCOL_ERR;
        }
    }
    else
    {

    }

    return status;
}

/////////////////////////////////////////////////////////////////////
//功    能：备份钱包
//参数说明: sourceaddr[IN]：源地址
//          goaladdr[IN]：目标地址
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char pcd_bak_value(unsigned char sourceaddr, unsigned char goaladdr)
{
    unsigned char crc_lsb = 0;
    unsigned char crc_msb = 0;
    int8_t status = MI_EMPTY;
    transceive_buffer  mf_com_data;
    transceive_buffer  *pi;
    pi = &mf_com_data;

    spi_write_reg(fifolevel_reg, 0x80);                    //clear fifo data
    spi_write_reg(recstate_reg, 0x7F);
    spi_write_reg(snd_byte_num_reg, 0x04);           //4bytes
    spi_write_reg(snd_bit_num_reg, 0x00);            //0bit

    mf_com_data.mf_command = PCD_TRANSCEIVE;
    mf_com_data.mf_length  = 4;
    mf_com_data.mf_data[0] = PICC_RESTORE;
    mf_com_data.mf_data[1] = sourceaddr;
    pcd_get_crc(CRC_A, 2, mf_com_data.mf_data, &crc_lsb, &crc_msb);
    mf_com_data.mf_data[2] = crc_lsb;
    mf_com_data.mf_data[3] = crc_msb;

    status = pcd_com_transceive(pi);


    if(MI_OK == status)
    {
        if(( mf_com_data.mf_data[0] & 0x0f) == 0x0A)                             //第二部分传输的数据时任意的，没意义的
        {
            spi_write_reg(fifolevel_reg, 0x80);                    //clear fifo data
            spi_write_reg(recstate_reg, 0x7F);
            spi_write_reg(snd_byte_num_reg, 0x06);
            spi_write_reg(snd_bit_num_reg, 0x00);

            mf_com_data.mf_command = PCD_TRANSMIT;
            mf_com_data.mf_length  = 6;
            memset(&mf_com_data.mf_data[0], 0, 4);
            pcd_get_crc(CRC_A, 4, mf_com_data.mf_data, &crc_lsb, &crc_msb);
            mf_com_data.mf_data[4] = crc_lsb;
            mf_com_data.mf_data[5] = crc_msb;

            status = pcd_com_transceive(pi);
            Delay_ms(40);//此时M1卡片也没回复，无需判断接收寄存器

            if(MI_OK == status)
            {
                status = pcd_transfer_block(goaladdr);

                if(MI_OK == status)
                {
                    return status;
                }
            }
            else
            {
                return status;
            }
        }
        else
        {
            return status;
        }
    }
    else
    {
        return status;
    }

    return status;
}


/**
 * @brief  transmission 数据透传
 * @param  length: 数据长度
 * @param  buf: 透传数据
 */
int8_t desocd_transmission(uint8_t *length,uint8_t *buf)
{
	int8_t status = MI_EMPTY;
  transceive_buffer  mf_com_data;
  transceive_buffer  *pi;
  pi = &mf_com_data;
	spi_write_reg(fifolevel_reg, 0x80);                    //clear fifo data
  spi_write_reg(recstate_reg, 0x7F);
	mf_com_data.mf_command =PCD_TRANSCEIVE;
	mf_com_data.mf_length  = length[0];
	memcpy(mf_com_data.mf_data,buf,length[0]);
	spi_write_reg(snd_byte_num_reg, mf_com_data.mf_length);
	spi_write_reg(snd_bit_num_reg, 0x00);
	status = pcd_com_transceive(pi);
	if(0x00 == status)
	{
		length[0] = mf_com_data.mf_length;
		memcpy(buf,mf_com_data.mf_data,mf_com_data.mf_length);
	}
	return status;
}